// Copyright 2010, Shuo Chen.  All rights reserved.
// http://code.google.com/p/muduo/
//
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.

// Author: Shuo Chen (chenshuo at chenshuo dot com)
//
// This is an internal header file, you should not include this.

#ifndef MUDUO_NET_TIMERQUEUE_H
#define MUDUO_NET_TIMERQUEUE_H

#include <set>
#include <vector>

#include <boost/noncopyable.hpp>

#include <muduo/base/Mutex.h>
#include <muduo/base/Timestamp.h>
#include <muduo/net/Callbacks.h>
#include <muduo/net/Channel.h>

namespace muduo
{
 namespace net
 {

  class EventLoop;

  class Timer;

  class TimerId;

///
/// A best efforts timer queue.
/// No guarantee that the callback will be on time.
///
  class TimerQueue : boost::noncopyable
  {
  public:
    TimerQueue(EventLoop *loop);

    ~TimerQueue();

    ///
    /// Schedules the callback to be run at given time,
    /// repeats if @c interval > 0.0.
    ///
    /// Must be thread safe. Usually be called from other threads.
    TimerId addTimer(const TimerCallback &cb,
                     Timestamp when,
                     double interval);

#ifdef __GXX_EXPERIMENTAL_CXX0X__

    TimerId addTimer(TimerCallback &&cb,
                     Timestamp when,
                     double interval);

#endif

    void cancel(TimerId timerId);

  private:

    // FIXME: use unique_ptr<Timer> instead of raw pointers.
    typedef std::pair<Timestamp, Timer *> Entry;
    typedef std::set<Entry> TimerList;
    typedef std::pair<Timer *, int64_t> ActiveTimer;
    typedef std::set<ActiveTimer> ActiveTimerSet;

    void addTimerInLoop(Timer *timer);

    void cancelInLoop(TimerId timerId);

    // called when timerfd alarms
    void handleRead();

    // move out all expired timers
    std::vector<Entry> getExpired(Timestamp now);

    void reset(const std::vector<Entry> &expired, Timestamp now);

    bool insert(Timer *timer);

    EventLoop *loop_;
    //timerfd_create创建。timefd_是linux中的一种机制，通过它可以将定时器事件和IO事件统一管理。因此我们可以像普通的文件描述符一样将timefd加入到epoll中，
    // 不过它的事件触发机制和普通的文件描述符不同，它是到达一定的设置时间后就会触发一个事件，时间可以由timerfd_settime库函数进行设置。
    const int timerfd_;
    Channel timerfdChannel_;
    // Timer list sorted by expiration
    //是一个multiset(平衡二叉树)，树中的元素是Timer，Timer是定时器对象
    TimerList timers_;

    // for cancel()
    ActiveTimerSet activeTimers_;
    bool callingExpiredTimers_; /* atomic */
    ActiveTimerSet cancelingTimers_;
  };

 }
}
#endif  // MUDUO_NET_TIMERQUEUE_H
